package com.example.administrator.demorecyclerview.refresh;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.NestedScrollingParent2;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ListViewCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;
import android.widget.OverScroller;
import android.widget.ProgressBar;
import android.widget.ScrollView;

import java.lang.reflect.Field;

/**
 * Created by Administrator on 2017/11/20.
 */

public class MySwipeRefreshLayout2 extends SwipeRefreshLayout implements NestedScrollingParent2 {

    boolean mLoading;
    private View mTarget;
    View mCircleView;
    private OnLoadListener mLoadListener;
    private ProgressBar mFooterProgress;
    private boolean mFinished;
    private OnChildScrollDownCallback mOnChildScrollDownCallback;
    private OnChildScrollUpCallback mOnChildScrollUpCallback;
    private OverScroller mScroller;

    public void setLoadingFinished(boolean finished) {
        mFinished = finished;
        setLoading(false);
    }

    public void setRefreshingFinished(boolean finished) {
        mFinished = finished;
        setRefreshing(false);
    }

    public MySwipeRefreshLayout2(@NonNull Context context) {
        this(context, null);
    }

    public MySwipeRefreshLayout2(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
//        mFooterProgress = new ProgressBar(getContext());
        mScroller = new OverScroller(getContext());
        try {
            Field f = getClass().getSuperclass().getDeclaredField("mCircleView");

            f.setAccessible(true);

            mCircleView = (View) f.get(this);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
//        createProgress();


        super.setOnChildScrollUpCallback(myOnChildScrollUpCallback);
//        setOnChildScrollDownCallback(myOnChildScrollDownCallback);

    }

    @Override
    public void setOnChildScrollUpCallback(@Nullable OnChildScrollUpCallback callback) {
//        super.setOnChildScrollUpCallback(callback);
        mOnChildScrollUpCallback = callback;
    }

    public void setOnChildScrollDownCallback(OnChildScrollDownCallback callback) {
        mOnChildScrollDownCallback = callback;
    }

    OnChildScrollUpCallback myOnChildScrollUpCallback = new OnChildScrollUpCallback() {
        @Override
        public boolean canChildScrollUp(@NonNull SwipeRefreshLayout parent, @Nullable View child) {

            if (isLoading()) {
                return true;
            } else {
                return mOnChildScrollUpCallback != null && mOnChildScrollUpCallback.canChildScrollUp(parent, child);
            }


        }
    };

    OnChildScrollDownCallback myOnChildScrollDownCallback = new OnChildScrollDownCallback() {
        @Override
        public boolean canChildScrollDown(@NonNull SwipeRefreshLayout parent, @Nullable View child) {
            if (isRefreshing() || isFinished()) {
                return true;
            } else {
                return mOnChildScrollDownCallback != null && mOnChildScrollDownCallback.canChildScrollDown(parent, child);
            }
        }
    };


    private void createProgress() {
        if (mFooterProgress == null) {
            mFooterProgress = new ProgressBar(getContext());
            mFooterProgress.setVisibility(View.GONE);
//            addView(mFooterProgress);
        }
    }


    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mTarget == null) {
            ensureTarget();
        }

        if (mFooterProgress != null) {
            mFooterProgress.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.AT_MOST));
        }

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (getChildCount() == 0) {
            return;
        }
        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }

        if (mFooterProgress == null) {
            createProgress();
            final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            addViewInLayout(mFooterProgress, getChildCount(), params, true);
            mFooterProgress.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.AT_MOST));
        }
        final int footerLeft = getPaddingLeft();
        final int footerTop = getMeasuredHeight() - getPaddingBottom();
        mFooterProgress.layout(footerLeft, footerTop, footerLeft + mFooterProgress.getMeasuredWidth(), footerTop + mFooterProgress.getMeasuredHeight());

    }


    private void ensureTarget() {

        if (mTarget == null) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (!child.equals(mCircleView)) {
                    mTarget = child;
                    break;
                }
            }
        }
    }


//    @Override
//    public void setRefreshing(boolean refreshing) {
//        if (mLoading) {
//            if (!refreshing) {
//                super.setRefreshing(false);
//            }
//        } else {
//            super.setRefreshing(refreshing);
//        }
//
//    }


    public boolean isLoading() {
        return mLoading;
    }


    public void setOnLoadListener(OnLoadListener listener) {
        mLoadListener = listener;
    }

    @Override
    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes, int type) {
        return onStartNestedScroll(child, target, axes);


    }

    @Override
    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes, int type) {
        onNestedScrollAccepted(child, target, axes);
    }

    @Override
    public void onStopNestedScroll(@NonNull View target, int type) {
        onStopNestedScroll(target);
    }


    @Override
    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
//        Log.i("@@@@@@@", "@@@@@@@@:onNestedScroll:"+dyUnconsumed+","+type);


        if (type == ViewCompat.TYPE_TOUCH) {
            onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        } else {
            dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
                    null);
        }
//
//        if (dyUnconsumed > 0 && !canChildScrollDown() && mScroller.isFinished()) {
//            mTotalUnconsumed -= dyUnconsumed;
////            Log.i("@@@","@@@@@@:"+mTotalUnconsumed);
//
////            moveFooter(Math.abs(mTotalUnconsumed));
//            final int offset = mTotalUnconsumed + mFooterProgress.getMeasuredHeight();
//            if (offset < 0) {
//                mTotalUnconsumed = -mFooterProgress.getMeasuredHeight();
//                moveFooter(-mTotalUnconsumed);
//            } else if (offset > 0) {
//                moveFooter(-mTotalUnconsumed);
//            }
//
//
////            scrollBy(0,dyUnconsumed);
//        }
    }

    @Override
    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @Nullable int[] consumed, int type) {
//        if (dy < 0 && mTotalUnconsumed < 0) {
//            if (dy < mTotalUnconsumed) {
//                consumed[1] = mTotalUnconsumed;
//                mTotalUnconsumed = 0;
//            } else {
//                mTotalUnconsumed -= dy;
//                consumed[1] = dy;
//            }
//            moveFooter(-mTotalUnconsumed);
//        }
//
//        if (dy < 0 && mTotalUnconsumed == 0
//                && dy - consumed[1] < 0) {
//            mFooterProgress.setVisibility(View.GONE);
//        }
//
        if (type == ViewCompat.TYPE_TOUCH) {
            onNestedPreScroll(target, dx, dy, consumed);
        } else {
//            dispatchNestedPreScroll(dx, dy, consumed, null);
            dispatchNestedPreScroll(dx, dy, consumed, null);
        }

    }


    public interface OnLoadListener {
        void onLoading();
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        ensureTarget();
        /**
         *
         * 如果正在loading或者loading结束后正在scrolling,onStartNestedScroll会返回false,此时会得到触摸时间，所以要判断mLoading||!mScroller.isFinished()
         * */
        if (canChildScrollDown() || mLoading || !mScroller.isFinished())
            return false;
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        /**
         *
         * 如果正在loading或者loading结束后正在scrolling,onStartNestedScroll会返回false,此时会得到触摸时间，所以要判断mLoading||!mScroller.isFinished()
         * */
        if (canChildScrollDown() || mLoading || !mScroller.isFinished())
            return false;

        return super.onTouchEvent(ev);
    }

    private int mTotalUnconsumed;



    public boolean isFinished() {
        return mFinished;
    }


    private void performeLoadingCallback() {
        if (mLoadListener != null) {
            mLoadListener.onLoading();
        }
    }

    public void setLoading(boolean loading) {
        if (loading && mLoading != loading) {
            setLoading(loading, true);
        } else {
            setLoading(loading, false);
        }
    }


    private void setLoading(boolean loading, boolean notify) {
        if (mLoading != loading) {
            ensureTarget();
            mLoading = loading;
            if (mLoading) {
                if (notify) {
                    performeLoadingCallback();
                }
            } else {
                resetLoading();
            }
        }
    }


    private void resetLoading() {
//        moveFooter(0);
//        Log.i("@@@@@@@", "@@@@@@@@:resetLoading:"+mTotalUnconsumed);

        mScroller.startScroll(0, mTotalUnconsumed, 0, -mTotalUnconsumed);

//        moveFooter(0);
//        mFooterProgress.setVisibility(GONE);
//        mTotalUnconsumed = 0;

        ViewCompat.postOnAnimation(this, mScrollRunnable);


//        ViewCompat.postInvalidateOnAnimation(this);

    }


    private final Runnable mScrollRunnable = new Runnable() {
        @Override
        public void run() {
            if (mScroller.computeScrollOffset()) {
//                Log.i("@@@@@@@", "@@@@@@@@:computeScroll:" + mScroller.getCurrY());

                mTotalUnconsumed = mScroller.getCurrY();
//                moveFooter(-mTotalUnconsumed);

                scrollTo(0, -mTotalUnconsumed);
                if (mTotalUnconsumed == 0) {
                    mFooterProgress.setVisibility(View.GONE);
                }


//                mTotalUnconsumed -= mScroller.getCurrY();


//                try {
//                    Thread.sleep(100);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }

//                moveFooter();

//                moveFooter(mTotalUnconsumed);
//                scrollTo(0,mScroller.getCurrY());

                ViewCompat.postOnAnimation(MySwipeRefreshLayout2.this, this);

            }
        }
    };


    @Override
    public void computeScroll() {
        super.computeScroll();
//        moveFooter(mScroller.getCurrY());


    }

    //    @Override
//    public boolean canChildScrollUp() {
//        boolean b = super.canChildScrollUp();
//        Log.i("@@@", "@@@@@@up:" + b);
//
//
//        return b;
//    }


    private void moveFooter(int y) {
        if (mFooterProgress.getVisibility() != VISIBLE) {
            mFooterProgress.setVisibility(VISIBLE);
        }
        scrollTo(0, y);

        if (y > 0) {
//            Log.i("@@@@@@@", "@@@@@@@:" + y);

//            performeLoadingCallback();
            setLoading(true, true);
        }

    }

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        if (!enabled) {
            resetLoading();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        resetLoading();
    }

    public boolean canChildScrollDown() {
        if (myOnChildScrollDownCallback != null) {
            return myOnChildScrollDownCallback.canChildScrollDown(this, mTarget);
        }
        if (mTarget instanceof ListView) {
            return ListViewCompat.canScrollList((ListView) mTarget, 1);
        }

//        Log.i("@@@", "@@@@@@down:" + mTarget.canScrollVertically(1));

        return mTarget.canScrollVertically(1);


//        return false;
    }

    public static class EarlyScrollListener extends RecyclerView.OnScrollListener {
        /**
         * RecyclerView滑动的时候，滑动到倒数几个的时候，进行预先loading
         */
        private int mEndNum;

        public EarlyScrollListener(MySwipeRefreshLayout2 refreshLayout, int endNum) {
            this.mRefreshLayout = refreshLayout;
            this.mEndNum = endNum;
        }

        MySwipeRefreshLayout2 mRefreshLayout;
        private int mState;
        private boolean mLastVisible;

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            mState = newState;
            doLoading();
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            final RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(recyclerView.getAdapter() == null ? -1 : recyclerView.getAdapter().getItemCount() - mEndNum);
            mLastVisible = viewHolder != null;
            doLoading();

        }

        private void doLoading() {
            if (!mRefreshLayout.isRefreshing() && !mRefreshLayout.isLoading() && mLastVisible && mState != RecyclerView.SCROLL_STATE_IDLE && !mRefreshLayout.isFinished()) {
                mRefreshLayout.setLoading(true);
            }
        }
    }

    public interface OnChildScrollDownCallback {
        boolean canChildScrollDown(@NonNull SwipeRefreshLayout parent, @Nullable View child);
    }

    //    @Override
//    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
//        boolean val = super.onStartNestedScroll(child, target, nestedScrollAxes);
//        Log.i("##", "onStartNestedScroll:" + val);
//        return val;
//    }
//
//    @Override
//    public void onNestedScrollAccepted(View child, View target, int axes) {
//        super.onNestedScrollAccepted(child, target, axes);
//        Log.i("##", "onNestedScrollAccepted:");
//
//    }

//    @Override
//    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
////        boolean val = super.onNestedPreFling(target, velocityX, velocityY);
////        Log.i("##", "onNestedPreFling:" + val + "," + velocityY);
////        return val;
//        return false;
//    }
//
//    @Override
//    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
//        boolean val = super.onNestedFling(target, velocityX, velocityY, consumed);
////        Log.i("##", "onNestedFling:" + val + "," + velocityY + "," + consumed);
//        return val;
//    }


//    @Override
//    public void onStopNestedScroll(View child) {
//        super.onStopNestedScroll(child);
//        Log.i("##", "onStopNestedScroll");
//    }
}
